package com.wondertek.poms.core.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Strings;
import com.wondertek.poms.common.constant.Constants;
import com.wondertek.poms.common.exception.BusinessException;
import com.wondertek.poms.common.exception.MessageCodes;
import com.wondertek.poms.common.service.impl.ServiceImpl;
import com.wondertek.poms.common.utils.CopyUtils;
import com.wondertek.poms.core.service.ISysDictDataService;
import com.wondertek.poms.dao.po.SysDictData;
import com.wondertek.poms.dao.repo.ISysDictDataDao;

import cn.hutool.core.collection.CollectionUtil;

/**
 * <p><b>SysDictDataServiceImpl Description:</b> 字典数据表service层实现 </p>
 *
 * @author wzq
 * <p><b>DATE</b> 2019-08-13 11:02:01</p>
 */
@Service
@Scope("prototype")
public class SysDictDataServiceImpl extends ServiceImpl<SysDictData, Long> implements ISysDictDataService {

    @Autowired
    private ISysDictDataDao dictDao;


    public Page<SysDictData> findAllData(SysDictData entity, int page, int rows, String sord, String sidx) {
        Pageable pageable = getPageable(page - 1, rows, sidx, sord);
        Specification<SysDictData> specification = getWhereClause(entity);
        return dictDao.findAll(specification, pageable);
    }

    @Override
    public SysDictData deleteLogic(Long id) {
        return null;
    }

    @CacheEvict(value = "poms-new:dict-type", key = "#dictData.type")
    @Override
    public SysDictData save(SysDictData dictData) {
        dictData = fillParentIdsAndIsLeaf(dictData);
        jpaRepository.save(dictData);
        return dictData;
    }

    @Cacheable(value = "poms-new:dict-type", key = "#type", unless = "#result==null")
    @Override
    public List<SysDictData> findAllByType(String type) {
        return dictDao.findAllByType(type);
    }

    @CacheEvict(value = "poms-new:dict-type", key = "#dictData.type")
    @Override
    @Transactional
    public void deleteById(SysDictData dictData) {
        jpaRepository.deleteById(dictData.getId());
    }

    @CacheEvict(value = "poms-new:dict-type", key = "#dictData.type")
    @Override
    @Transactional
    public String deleteLogic(SysDictData dictData) {
        //首先查找父节点，如果父节点已经被删除或禁用，则子节点不能被启用
        String msg="";
        if (dictData.getParentId() != 0) {
            SysDictData parentData = dictDao.getOne(dictData.getParentId());
            if (parentData.getDeleted() != Constants.DELETE_0 && dictData.getDeleted() == Constants.DELETE_0) {
                msg="父节点已经被删除或禁用，该节点不能被启用";
            }
        }
        //删除之前查询有没有子节点，如果有子节点 把所有子节点都删除
        List<SysDictData> allChildList = dictDao.findByParentIdsLike(dictData.getId());
        //如果父节点下面还有子节点未被删除或禁用，则不能禁用该父节点
        if (dictData.getDeleted() == Constants.DELETE_2) {
            if (allChildList != null && allChildList.size() > 0) {
                msg="该节点存在子节点未被删除或禁用";
            }
        }
        if (CollectionUtil.isNotEmpty(allChildList)) {
            for (SysDictData childData : allChildList) {
                deleteAndStopLogic(childData.getId(), dictData.getDeleted());
            }
        }
        deleteAndStopLogic(dictData.getId(), dictData.getDeleted());
        return msg;
    }

    @Override
    public List<SysDictData> getByParentId(Long parentId) {
        return dictDao.findByParentIdAndDeleted(parentId);
    }

    @Override
    @Transactional
    public SysDictData deleteAndStopLogic(Long id, Integer status) {
        SysDictData cp = jpaRepository.getOne(id);
        SysDictData.putTimeAndUser(cp);
        cp.setDeleted(status);
        jpaRepository.save(cp);
        return cp;
    }

    @Override
    @Transactional
    @CacheEvict(value = "poms-new:dict-type", key = "#dictData.type")
    public SysDictData merge(SysDictData dictData) {
        if (dictData.getParentId() != null) {
            dictData = updateParentIdsAndIsLeaf(dictData);
        }
        SysDictData.putTimeAndUser(dictData);
        SysDictData dbo = jpaRepository.getOne(dictData.getId());
        CopyUtils.copyProperties(dictData, dbo);
        return jpaRepository.save(dbo);
    }

    @SuppressWarnings("serial")
    private Specification<SysDictData> getWhereClause(final SysDictData dictData) {
        return new Specification<SysDictData>() {

            @Override
            public Predicate toPredicate(Root<SysDictData> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicate = new ArrayList<>();

                if (!Strings.isNullOrEmpty(dictData.getType())) {
                    predicate.add(cb.equal(root.get("type"),dictData.getType()));
                }
                if (!Strings.isNullOrEmpty(dictData.getDescription())) {
                    predicate.add(cb.like(root.get("description"), "%" + dictData.getDescription() + "%"));
                }
                if (null != dictData.getParentId()) {
                    predicate.add(cb.equal(root.get("parentId"), dictData.getParentId()));
                }
                if (!Strings.isNullOrEmpty(dictData.getLabel())) {
                    predicate.add(cb.like(root.get("label"), "%" + dictData.getLabel() + "%"));
                }
                if (!Strings.isNullOrEmpty(dictData.getValue())) {
                    predicate.add(cb.like(root.get("value"), "%" + dictData.getValue() + "%"));
                }
                if (null != dictData.getDeleted()) {
                    predicate.add(cb.equal(root.get("deleted"), dictData.getDeleted()));
                }
                Predicate[] pre = new Predicate[predicate.size()];
                return query.where(predicate.toArray(pre)).getRestriction();
            }
        };
    }

    /***
     * @Author wzq
     * @Description //新增时填充parentIds和isLeaf字段
     * parentIds是父级所有parentid的集合以，分割  isleaf可判断是否是叶子节点
     * @Date 18:20 2019/8/14
     * @Param [dictData]
     * @return void
     **/
    public SysDictData fillParentIdsAndIsLeaf(SysDictData dictData) {
        //新增的时候把上层的所有id都存到parentIds字段
        if (dictData.getParentId() != 0) {
            SysDictData pData = findById(dictData.getParentId());
            dictData.setParentIds(pData.getParentIds() + "," + pData.getId());
        } else {
            dictData.setParentIds("0");
        }

        //新增的时候isleaf置为1，并把父节点的isleaf置为0
        dictData.setLastLeaf("1");
        if (dictData.getParentId() != 0) {
            SysDictData parentDictData = findById(dictData.getParentId());
            parentDictData.setLastLeaf("0");
            SysDictData.putTimeAndUser(parentDictData);
            jpaRepository.save(parentDictData);
        }
        return dictData;
    }

    /***
     * @Author wzq
     * @Description //修改的时候需要考虑到的问题
     * 1.如果修改了parentId的话  那我们需要考虑此节点的父节点是否还存在叶子节点，如果不存在，则把isleaf置为1
     * 2.修改过之后的节点如果原本是叶子节点，则现在要被置成父节点isleaf为0
     * 3.修改此节点的parentid，parentids为新的节点的id,如果此节点下面还有孩子节点，把孩子节点的parentids也需要更新
     * @Date 9:32 2019/8/19
     * @Param [dictData]
     * @return com.wondertek.oes.charge.common.po.SysDictData
     **/
    public SysDictData updateParentIdsAndIsLeaf(SysDictData dictData) {
        //修改时需要把父节点的parentids更新
        //如果不是一级节点
        if (dictData.getParentId() != 0) {
            //获取修改之前的那个节点，判断它是否还有子节点，如果没有就是子节点 isleaf置为1
            SysDictData oldData = findById(dictData.getId());
            List<SysDictData> allByParentId = dictDao.findAllByParentId(oldData.getParentId(), oldData.getId());
            if (allByParentId == null || allByParentId.size() == 0) {
                SysDictData dictData1 = findById(oldData.getParentId());
                dictData1.setLastLeaf("1");
                SysDictData.putTimeAndUser(dictData1);
                jpaRepository.save(dictData1);
            }
            //修改的新节点如果是叶子节点，需要修改为isleaf为0
            SysDictData pData = findById(dictData.getParentId());
            pData.setLastLeaf("0");
            SysDictData.putTimeAndUser(pData);
            jpaRepository.save(pData);

            //更新本节点的parentIds,如果这个节点不是叶子节点，需要把他的子节点的parentids也全部修改
            dictData.setParentIds(pData.getParentIds() + "," + pData.getId());
            List<SysDictData> childNodesList = dictDao.findByParentIdsLike(dictData.getId());
            for (SysDictData childData : childNodesList) {
                childData.setParentIds(dictData.getParentIds() + "," + dictData.getId());
                SysDictData.putTimeAndUser(childData);
                jpaRepository.save(childData);
            }
        } else {
            dictData.setParentIds("0");
        }
        return dictData;
    }
}